startTestGroup('Implementing Interfaces');

window.x = '';
window.IInterface = '';
window.success = false;
window.implClass = '';

// An interface should not be instantiated
IInterface = jInterface({
    test : function() {},
    test1 : function(param) {},
    undef : function() {}
});

success = false;
try { x = new IInterface(); } catch (ex) { success = ex.message == 'Cannot instantiate an interface'; }
assertTrue('Trying to instantiate an interface should fail', success);

success = false;
try { tmp = jInterface({ test : function() { var a = 2; } }); } catch (ex) { success = ex.message == "Interface must not implement a method body (test)"; }
assertTrue('Trying to write a body to a interface method should fail', success);

success = false;
try { jClass.implement({})({}) } catch (ex) { success = ex.message == 'Not an interface';}
assertTrue('Tring to implement a non jInterface object should fail', success);

success = false;
try { jClass.implement(IInterface)({ public : {a :2}}); } catch (ex) { success = ex.message == "Interface member (test) not implemented by class"; }
assertTrue('Tring to create a class that doesn\'t implement required method should fail', success);

success = false;
try { jClass.implement(IInterface)({ public : {test : 2}}); } catch (ex) { success = ex.message == "Interface member (test) not implemented by class"; }
assertTrue('Tring to create a class that doesn\'t implement required method type fail', success);

success = false;
try { jClass.implement(IInterface)({ public : {test : function(){}, test1 : function(param,param1) {}}}); } catch (ex) {  success = ex.message == "Interface member (test1) arguments count does not match implementation. (Expected 1, got 2)"; }
assertTrue('Tring to create a class that doesn\'t implement required number of arguments for a metehod should fail', success);

success = false;
try { jClass.extend(BaseClass).implement(IInterface)({public:{}}); }catch (ex) {  success = ex.message == "Interface member (test1) not implemented by class"; }
assertTrue("Depending on a inheritence implementation", success);

success = false;
try { jClass.extend(ExtendingClass).implement(IInterface)({ public : { test1: function(arg) {} } }); }catch (ex) { success = ex.message == "Interface member (undef) not implemented by class"; }
assertTrue("Overriding inheritence to meet interface", success);

implClass = jClass.extend(ExtendingClass).implement(IInterface)({ public : { test1: function(arg) {}, undef : function() {} } });
x = new implClass();
assertTrue("Class is implementation of IInterface", x.isImplementationOf(IInterface));
assertTrue("Class is instance of ExtendingClass, BaseClass of IInterface", x.isInstanceOf(ExtendingClass), x.isInstanceOf(BaseClass));
assertTrue('Accessing public member from both ExtendingClass and BaseClass', x.pMethod(), x.pVar == 2, x.extpVar == 2, x.extpMethod());
assertTrue('Class should contain inherited statics', implClass.STATIC, implClass.stat, implClass.EXT_STATIC, implClass.extstat);
assertNull('Class instance should not contain inherited statics', x.STATIC, x.stat, x.EXT_STATIC, x.extstat);
assertNull('Accessing private member should return undefined', x.extprivVar, x.extprivMethod, x.privVar, x.privMethod);
assertTrue('Accessing inherited public method that reads from BaseClass private space', x.retPrivate());
x.setter = 3;
assertNull('Testing WriteOnly properties in BaseClass', (x.getSetter() == 3 ? undefined : '!='), x.setter);
success = false;
try { x.getter = 2; } catch(ex) { success = (ex.message == "Property is Read-Only"); }
assertTrue('Testing ReadOnly properties in BaseClass', x.getter == 2, success);
assertTrue('Testing Overloading methods in BaseClass', x.overload() == 0, x.overload(1) == 1, x.overload(1,2) == 2, x.overload(1,2,3,4,5) == 5, x.overload(1,2,3) == 2, x.overload(1,2,3,4,5,6) == 5);

delete(x);
delete(extendingClassInstances);
delete(baseClassInstances);
delete(implClass);
delete(IInterface);
delete(success);
delete(BaseClass);
delete(ExtendingClass);
delete(TempExt);
